# !/usr/bin python3
import time

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait

import get_project_path
from common.logger import GetLogger


class InitDriver:
    """
    现在咱们封装的这个类对象，将会代替学基础的时候的driver对象，并且该对象还能直接完成各种动作
    """

    def __init__(self, browser='chrome', remote_url=None):
        self.logger = GetLogger.get_logger()
        self.browser = browser.lower()
        if remote_url == None:
            if self.browser == 'chrome':
                options = Options()
                options.debugger_address = 'localhost:9222'
                executable_path = f"{get_project_path.project_path}\webDriver\chromedriver.exe"
                self.driver = webdriver.Chrome(executable_path=executable_path)
            elif self.browser == 'firefox':
                self.driver = webdriver.Firefox()
            elif self.browser == 'ie':
                self.driver = webdriver.Ie()
            elif self.browser == 'edge':
                self.driver = webdriver.Edge()
            elif self.browser == 'safari':
                self.driver = webdriver.Safari()
            else:
                self.logger.error(f'不支持{self.browser}浏览器')
                raise BaseException(f'不支持{self.browser}浏览器')
        else:
            if self.browser == 'chrome':
                # self.driver = webdriver.Chrome()
                options = webdriver.ChromeOptions()
            elif self.browser == 'firefox':
                # self.driver = webdriver.Firefox()
                options = webdriver.FirefoxOptions()
                options.add_argument('--no-sandbox')
            elif self.browser == 'ie':
                # self.driver = webdriver.Ie()
                options = webdriver.IeOptions()
            elif self.browser == 'edge':
                pass
                # self.driver = webdriver.Edge()
                # pip install msedge-selenium-tools==3.141.3 -i https://pypi.douban.com/simple
                # from msedge.selenium_tools import EdgeOptions
                # options = EdgeOptions()
            # elif self.browser == 'safari':
            #     self.driver = webdriver.Safari()
            else:
                self.logger.error(f'不支持{self.browser}浏览器')
                raise BaseException(f'不支持{self.browser}浏览器')
            self.driver = webdriver.Remote(remote_url, desired_capabilities=options.to_capabilities())
        # 浏览器最大化
        # print(f'{self.browser}浏览器启动成功')
        self.driver.implicitly_wait(10)  # 统一的隐式等待10s中
        self.logger.info(f'{self.browser}浏览器启动成功')

    def set_window_size(self, width=None, height=None):
        if width and height:
            self.driver.set_window_size(width, height)
        else:
            self.driver.maximize_window()

    # 封装各种各样的操作
    def get(self, url):
        """
        打开某个网址
        :param url:
        :return:
        """
        self.driver.get(url=url)
        self.logger.info(f'{url}打开成功')

    # 本身webdriver对象就有这些动作，为什么还要去封装？
    # 1.增加日志
    # 2.让操作能够更加适配未来我们的封装

    def find_element(self, ele_info):
        # 设计每个元素的基本信息如下
        # ele_info = {"name":"登录链接","type":"linktext","value":"登录","timeout":5}
        name = ele_info['name']  # 获取元素名称
        type = ele_info['type'].lower()  # 获取元素的定位类型
        value = ele_info['value']  # 获取元素定位的值
        timeout = ele_info['timeout']  # 获取元素定位的超时时间

        # 查找方法需要根据不同的定位类型来决定传入的是八大定位的哪一种
        locator = self.get_by(ele_info)
        try:
            wait = WebDriverWait(driver=self.driver, timeout=timeout)
            element = wait.until(expected_conditions.presence_of_element_located(locator))
            # self.logger.info(f'定位元素【{name}】,通过【{type}】方式，值是【{value}】,定位成功')
        except BaseException as e:
            self.logger.exception(f'定位元素【{name}】,通过【{type}】方式，值是【{value}】,定位失败')
            raise BaseException(f'定位元素【{name}】,通过【{type}】方式，值是【{value}】,定位失败：{e}')
        return element

    def find_elements(self, ele_info):
        # 设计每个元素的基本信息如下
        # ele_info = {"name":"登录链接","type":"linktext","value":"登录","timeout":5}
        name = ele_info['name']  # 获取元素名称
        type = ele_info['type'].lower()  # 获取元素的定位类型
        value = ele_info['value']  # 获取元素定位的值
        timeout = ele_info['timeout']  # 获取元素定位的超时时间

        locator = self.get_by(ele_info)
        try:
            wait = WebDriverWait(driver=self.driver, timeout=timeout)
            eles_list = wait.until(expected_conditions.presence_of_all_elements_located(locator))
            self.logger.info(f'定位元素【{name}】,通过【{type}】方式，值是【{value}】,定位到{len(eles_list)}个')
        except BaseException as e:
            self.logger.exception(f'定位元素【{name}】,通过【{type}】方式，值是【{value}】,定位失败')
            raise BaseException(f'定位元素【{name}】,通过【{type}】方式，值是【{value}】,定位失败：{e}')
        return eles_list

    # 把判断元素类型这部分单独抽出作为一个方法
    def get_by(self, ele_info):
        type = ele_info['type'].lower()  # 获取元素的定位类型
        value = ele_info['value']  # 获取元素定位的值
        # 查找方法需要根据不同的定位类型来决定传入的是八大定位的哪一种
        if type == 'id':
            locator = (By.ID, value)
        elif type == 'name':
            locator = (By.NAME, value)
        elif type == 'classname':
            locator = (By.CLASS_NAME, value)
        elif type == 'linktext':
            locator = (By.LINK_TEXT, value)
        elif type == 'partiallinktext':
            locator = (By.PARTIAL_LINK_TEXT, value)
        elif type == 'tagname':
            locator = (By.TAG_NAME, value)
        elif type == 'css' or type == 'cssselector':
            locator = (By.CSS_SELECTOR, value)
        elif type == 'xpath':
            locator = (By.XPATH, value)
        else:
            self.logger.error(f'定位类型【{type}】不支持')
            raise BaseException(f'定位类型【{type}】不支持')
        return locator

    def click(self, ele_info):
        name = ele_info['name']  # 获取元素名称
        type = ele_info['type'].lower()  # 获取元素的定位类型
        value = ele_info['value']  # 获取元素定位的值
        timeout = ele_info['timeout']  # 获取元素定位的超时时间
        # locator = self.get_by(ele_info)
        elememt = self.find_element(ele_info)
        try:
            wait = WebDriverWait(driver=elememt, timeout=timeout)
            wait.until(element_click_success())
            self.logger.info(f'点击元素【{name}】,通过【{type}】方式，值是【{value}】,点击成功')
        except BaseException as e:
            self.logger.exception(f'点击元素【{name}】,通过【{type}】方式，值是【{value}】,点击失败')
            raise BaseException(f'点击元素【{name}】,通过【{type}】方式，值是【{value}】,点击失败：{e}')

    def clicks(self, ele_info):
        elememts = self.find_elements(ele_info)
        name = ele_info['name']  # 获取元素名称
        type = ele_info['type'].lower()  # 获取元素的定位类型
        value = ele_info['value']  # 获取元素定位的值
        timeout = ele_info['timeout']  # 获取元素定位的超时时间
        try:
            for elem in elememts:
                wait = WebDriverWait(driver=elem, timeout=timeout)
                wait.until(element_click_success())
            self.logger.info(f'点击元素【{name}】,通过【{type}】方式，值是【{value}】,点击成功')
        except BaseException as e:
            self.logger.exception(f'点击元素【{name}】,通过【{type}】方式，值是【{value}】,点击失败')
            raise BaseException(f'点击元素【{name}】,通过【{type}】方式，值是【{value}】,点击失败：{e}')

    def send_keys(self, ele_info, text):
        elememt = self.find_element(ele_info)
        name = ele_info['name']  # 获取元素名称
        type = ele_info['type'].lower()  # 获取元素的定位类型
        value = ele_info['value']  # 获取元素定位的值
        timeout = ele_info['timeout']  # 获取元素定位的超时时间
        try:
            elememt.clear()  # 先清除输入框原有内容
            elememt.send_keys(text)
            self.logger.info(f'向元素【{name}】,通过【{type}】方式，输入【{value}】，值是【{text}】,成功')
        except BaseException as e:
            self.logger.exception(f'向元素【{name}】,通过【{type}】方式，输入【{value}】，值是【{text}】,,失败')
            raise BaseException(f'向元素【{name}】,通过【{type}】方式，输入【{value}】，值是【{text}】,失败')

    def send_keyss(self, ele_info, text):
        elememts = self.find_elements(ele_info)
        name = ele_info['name']  # 获取元素名称
        type = ele_info['type'].lower()  # 获取元素的定位类型
        value = ele_info['value']  # 获取元素定位的值
        timeout = ele_info['timeout']  # 获取元素定位的超时时间
        try:
            for elememt in elememts:
                elememt.clear()  # 先清除输入框原有内容
                elememt.send_keys(text)
            self.logger.info(f'向元素【{name}】,通过【{type}】方式，输入【{value}】，值是【{text}】,成功')
        except BaseException as e:
            self.logger.exception(f'向元素【{name}】,通过【{type}】方式，输入【{value}】，值是【{text}】,,失败')
            raise BaseException(f'向元素【{name}】,通过【{type}】方式，输入【{value}】，值是【{text}】,失败')
    def page_contains(self, text, timeout=5):
        """
        在一定时间内，判断页面是否包含某段文字
        :param text:
        :param timeout:
        :return:
        """
        wait = WebDriverWait(driver=self.driver, timeout=timeout)
        try:
            wait.until(lambda d: text in d.page_source)
            return True
        except BaseException as e:
            return False

    def move_to_element(self, ele_info):
        """
        鼠标移动到某个元素
        :param ele_info:
        :return:
        """
        action = ActionChains(self.driver)
        element = self.find_element(ele_info)
        action.move_to_element_with_offset(element, 0, 10).release().perform()
        self.logger.info(f'移动到元素【{ele_info["name"]}】成功,元素info:【{self.get_text(ele_info)}】')

    def action_keys(self, keys, *keys_to_send):
        """
        模拟按下回车键
        :return:
        """
        action = ActionChains(self.driver)
        action.send_keys(keys, *keys_to_send).perform()

    def context_click(self, ele_info):
        """
        模拟鼠标右键点击
        :return:
        """
        # 定位到需要右键点击的元素
        element = self.find_element(ele_info)
        action = ActionChains(self.driver)
        action.context_click(element).perform()

    def get_screenshot_as_png(self):
        # 得到的是截图的一个二进制对象，并不会存储文件到本地
        return self.driver.get_screenshot_as_png()

    def get_screenshot_as_file(self, filename):
        self.driver.get_screenshot_as_file(filename)

    def switch_to_window(self, index=1):
        window_handles = self.driver.window_handles
        self.driver.switch_to.window(window_handles[index])

    def close_until_one_window(self):
        window_handles = self.driver.window_handles
        for i in range(1, len((window_handles))):  # 从第二个窗口开始关闭
            self.driver.switch_to.window(window_handles[i])
            self.driver.close()
        self.driver.switch_to.window(window_handles[0])

    def quit(self):
        self.driver.quit()

    def get_text(self, ele_info):
        element = self.find_element(ele_info)
        return element.text

    def get_attribute(self, ele_info, attr_name):
        element = self.find_element(ele_info)
        return element.get_attribute(attr_name)

    def is_element_exists(self, ele_info):
        try:
            self.driver.find_element(ele_info)
            return True
        except:
            return False

    def get_css(self, ele_info, css_name):
        element = self.find_element(ele_info)
        return element.value_of_css_property(css_name)
        # self.driver.find_element(By.ID,'xxx').value_of_css_property()

    def get_url(self):
        return self.driver.current_url
        # self.driver.find_element(By.ID,'xxx').value_of_css_property()

    def get_location(self, ele_info):
        element = self.find_element(ele_info)
        return element.location

    def add_cookie(self, cookie):
        self.driver.add_cookie(cookie)

    def execute_script(self, script, *args):
        self.driver.execute_script(script, *args)


class element_click_success(object):
    """ An Expectation for checking an element is visible and enabled such that
    you can click it."""

    # def __init__(self, element):
    #     self.locator = element
    def __call__(self, element):  #
        # element = driver.find_element(*self.locator)
        try:
            element.click()
            return True
        except:
            # print('点了有异常，隔0.5秒继续点')
            return False


# 定义个全局性的driver变量，他代表所有用的相同的driver对象
class GlobalDriver:
    # 这个类属性globalDriver代表了所有用到的公共的driver对象
    # 定义时他是None，那么在什么地方给他赋值呢
    # 在conftest.py中自定义一个fixture来实现全局driver初始化
    globalDriver: InitDriver = None


if __name__ == '__main__':
    driver = InitDriver()
    # driver.get('file:///C:/Users/EDY/Desktop/new_web_nuwanwa.html')
    driver.get('http://ab-crm-web-admin.test.nuanwa-tech.net/')
    driver.set_window_size(1024, 1024)
    script = "window.scrollTo(0, document.body.scrollHeight+600);"
    driver.execute_script(script)

